#region Usings
using System;
using Lib.Exceptions;
using Lib.Utils.Collections;
#endregion

namespace Bk.Import.CashOrganizer
{
    public class CoInfoBlock : CustomList<string>
    {
        #region Fields
        private int _amountIndex;
        private CoInfoBlockType? _blockType;
        private int _categoryIndex;
        private int _dateIndex;
        private int _nameIndex;
        private int _payeeIndex;
        #endregion

        #region C'tors
        public CoInfoBlock()
        {
            _blockType = null;
            _nameIndex = -1;
            _dateIndex = -1;
            _payeeIndex = -1;
            _amountIndex = -1;
            _categoryIndex = -1;
        }

        public CoInfoBlock(CoInfoBlockType blockType) : this(null, blockType)
        {
        }

        public CoInfoBlock(CoInfoBlock infoBlock, CoInfoBlockType blockType)
        {
            _blockType = blockType;
            if (infoBlock != null)
            {
                AddRange(infoBlock);
            }
        }
        #endregion

        #region Instance Methods
        public new void Add(string item)
        {
            if (!string.IsNullOrEmpty(item))
            {
                base.Add(item);

                if (!_blockType.HasValue)
                {
                    if (!DetermineBlockType(item))
                    {
                        DetermineIndexes(item);
                    }
                }
                else
                {
                    DetermineIndexes(item);
                }
            }
        }

        private bool DetermineBlockType(string item)
        {
            if (item.IndexOf(CoConstants.INFO_BLOCK_ACCOUNT) == 0)
            {
                _blockType = CoInfoBlockType.Account;
            }
            else if ((Count == 0) && (item == CoConstants.INFO_BLOCK_TYPE_BANK))
            {
                _blockType = CoInfoBlockType.TypeBank;
            }
            return _blockType.HasValue;
        }

        private void DetermineIndexes(string item)
        {
            DetermineNumber(item, "N", ref _nameIndex);
            DetermineNumber(item, "D", ref _dateIndex);
            DetermineNumber(item, "P", ref _payeeIndex);
            DetermineNumber(item, "T", ref _amountIndex);
            DetermineNumber(item, "L", ref _categoryIndex);
        }

        private void DetermineNumber(string item, string key, ref int number)
        {
            if (number == -1)
            {
                if (item.IndexOf(key) == 0)
                {
                    number = Count - 1;
                }
            }
        }

        private DateTime GetDateFromCoString(string dateString)
        {
            int indexOfPoint = dateString.IndexOf('.');
            if (indexOfPoint == -1)
            {
                throw new ArgumentException(string.Format("There is no '.' in string {0}", dateString));
            }
            else
            {
                string stringMonth = dateString.Substring(1, indexOfPoint - 1);
                int indexOfApostrof = dateString.IndexOf('\'');
                if (indexOfApostrof == -1)
                {
                    throw new ArgumentException(string.Format("There is no '{0}' in string {1}", '\'', dateString));
                }
                else
                {
                    string stringDay = dateString.Substring(indexOfPoint + 1, indexOfApostrof - indexOfPoint - 1);

                    string stringYear = dateString.Substring(indexOfApostrof + 1,
                                                             dateString.Length - indexOfApostrof - 1);

                    return new DateTime(2000 + int.Parse(stringYear), int.Parse(stringMonth), int.Parse(stringDay));
                }
            }
        }
        #endregion

        #region Instance Properties
        public CoInfoBlockType? BlockType
        {
            get { return _blockType; }
        }

        public bool IsEmpty
        {
            get { return Count == 0; }
        }

        protected decimal Amount
        {
            get
            {
                if (_amountIndex == -1)
                {
                    throw new NotDefinedException("Index of Amount is not defined");
                }
                return decimal.Parse(this[_amountIndex].Substring(1, this[_amountIndex].Length - 1));
            }
            set { this[_amountIndex] = string.Format("T{0}", value); }
        }

        protected string Category
        {
            get
            {
                if (_categoryIndex == -1)
                {
                    throw new NotDefinedException("Index of Category is not defined");
                }

                return this[_categoryIndex].Substring(1, this[_categoryIndex].Length - 1);
            }
            set { this[_categoryIndex] = string.Format("L{0}", value); }
        }

        protected DateTime Date
        {
            get
            {
                if (_dateIndex == -1)
                {
                    throw new NotDefinedException("Index of Date is not defined");
                }
                return GetDateFromCoString(this[_dateIndex]);
            }
            set { this[_nameIndex] = string.Format("D{0}.{1}'{2}", value.Month, value.Day, value.Year - 2000); }
        }

        protected string Name
        {
            get
            {
                if (_nameIndex == -1)
                {
                    throw new NotDefinedException("Index of Name is not defined");
                }
                return this[_nameIndex].Substring(1, this[_nameIndex].Length - 1);
            }
            set { this[_nameIndex] = string.Format("N{0}", value); }
        }

        /// <summary>
        /// Account in BookKeeper system
        /// </summary>
        protected string Payee
        {
            get
            {
                if (_payeeIndex == -1)
                {
                    throw new NotDefinedException("Index of Payee is not defined");
                }
                return this[_payeeIndex].Substring(1, this[_payeeIndex].Length - 1).TrimStart('[').TrimEnd(']');
            }
            set { this[_payeeIndex] = string.Format("P[{0}]", value); }
        }
        #endregion
    }
}